﻿using System;
using System.IO;

namespace UtilsExtensionsAndHelpers.Helpers.Implimentations
{
    public class FileHelper : IFileHelper
    {
        private Func<Exception, bool> _errorHandler;
        /// <summary>
        /// Get ot set the method to handle errors. This should return 
        /// a boolean value, true rethrow error, false don't.
        /// </summary>
        public Func<Exception, bool> ErrorHandler
        {
            get { return _errorHandler ?? (_errorHandler = e => true); }
            set { _errorHandler = value; }
        }

        /// <summary>
        /// Creates the needed parent directories if they don't exist.
        /// </summary>
        /// <param name="filePath">Name to the file you want the parent directory path created for.</param>
        public void EnsureParentDirExists(string filePath)
        {
            var file = new FileInfo(filePath);
            var parentDirectory = file.DirectoryName;
            EnsureDirExists(parentDirectory);
        }

        /// <summary>
        /// Creates the needed parent directories if they don't exist.
        /// </summary>
        /// <param name="dirPath">Name to the dir you want the parent directory path created for.</param>
        public void EnsureDirExists(string dirPath)
        {
            try {
                if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
            } catch (Exception e) {
                var rethrow = ErrorHandler(e);
                if (rethrow) throw;
            }
        }

        /// <summary>
        /// Reads through a file line by line till it hits an ending marker, then passes what it's found to the action.
        /// After passing a string to the action, it clears and starts again. Very handy for xml lists. Just set the ending
        /// tag as the endingMarker.
        /// </summary>
        /// <param name="filePath">Full path to the file being read.</param>
        /// <param name="endingMarker">A string marking the end of a section</param>
        /// <param name="action">What you want to do with the string</param>
        public void ReadThroghFile(string filePath, string endingMarker, Action<string> action)
        {
            ReadThroghFile(filePath, 0, endingMarker, action);
        }

        /// <summary>
        /// Reads through a file line by line till it hits an ending marker, then passes what it's found to the action.
        /// After passing a string to the action, it clears and starts again. Very handy for xml lists. Just set the ending
        /// tag as the endingMarker.
        /// </summary>
        /// <param name="filePath">Full path to the file being read.</param>
        /// <param name="beingLinesToSkip">If you need to skip any lines, like DTD</param>
        /// <param name="endingMarker">A string marking the end of a section</param>
        /// <param name="action">What you want to do with the string</param>
        public void ReadThroghFile(string filePath, int beingLinesToSkip, string endingMarker, Action<string> action)
        {
            ReadThroghFile(filePath, beingLinesToSkip, endingMarker, action, ErrorHandler);
        }
        /// <summary>
        /// Reads through a file line by line till it hits an ending marker, then passes what it's found to the action.
        /// After passing a string to the action, it clears and starts again. Very handy for xml lists. Just set the ending
        /// tag as the endingMarker.
        /// </summary>
        /// <param name="filePath">Full path to the file being read.</param>
        /// <param name="beingLinesToSkip">If you need to skip any lines, like DTD</param>
        /// <param name="endingMarker">A string marking the end of a section</param>
        /// <param name="action">What you want to do with the string</param>
        /// <param name="errorHandler">A method to handle error, return true to rethow error false to swallow</param>
        public void ReadThroghFile(string filePath, int beingLinesToSkip, string endingMarker, Action<string> action, Func<Exception, bool> errorHandler)
        {
            using (var feed = new StreamReader(filePath))
            {
                var currentLine = String.Empty;
                var runningString = String.Empty;

                for (var i = 0; i < beingLinesToSkip; i++) feed.ReadLine(); //get past the feed header

                while ((currentLine = feed.ReadLine()) != null)
                {
                    runningString += currentLine;
                    if (!currentLine.Contains(endingMarker)) continue;

                    try {
                        action(runningString);
                    } catch (Exception ex) {
                        var rethrow = errorHandler(ex);
                        if (rethrow) throw;
                    }
                    runningString = String.Empty;
                }
            }
        }

        /// <summary>
        /// Reads through a file line by line, passing each line to the action.
        /// Very handy for CSV for any other text files. 
        /// </summary>
        /// <param name="filePath">Full path to the file being read.</param>
        /// <param name="action">What you want to do with the string</param>
        public void ReadThroghFileByLine(string filePath, Action<string> action)
        {
            ReadThroghFileByLine(filePath, 0, action, ErrorHandler);
        }
        /// <summary>
        /// Reads through a file line by line, passing each line to the action.
        /// Very handy for CSV for any other text files. 
        /// </summary>
        /// <param name="filePath">Full path to the file being read.</param>
        /// <param name="beingLinesToSkip">If you need to skip any lines, like CSV hearers</param>
        /// <param name="action">What you want to do with the string</param>
        public void ReadThroghFileByLine(string filePath, int beingLinesToSkip, Action<string> action)
        {
            ReadThroghFileByLine(filePath, beingLinesToSkip, action, ErrorHandler);
        }
        /// <summary>
        /// Reads through a file line by line, passing each line to the action.
        /// Very handy for CSV for any other text files. 
        /// </summary>
        /// <param name="filePath">Full path to the file being read.</param>
        /// <param name="beingLinesToSkip">If you need to skip any lines, like CSV hearers</param>
        /// <param name="action">What you want to do with the string</param>
        /// <param name="errorHandler">A method to handle error, return true to rethow error false to swallow</param>
        public void ReadThroghFileByLine(string filePath, int beingLinesToSkip, Action<string> action, Func<Exception,bool> errorHandler)
        {
            using (var feed = new StreamReader(filePath))
            {
                var currentLine = String.Empty;

                for (var i = 0; i < beingLinesToSkip; i++) feed.ReadLine(); //get past the feed header

                while ((currentLine = feed.ReadLine()) != null)
                {
                    try {
                        action(currentLine);
                    } catch (Exception ex) {
                        var rethrow = errorHandler(ex);
                        if (rethrow) throw; 
                    }
                }
            }
        }
    }
}
